import es
import langlib
import weaponlib

from wcs.libs.races.base import RaceBase
from wcs.libs.constants import *
from wcs.libs.config import *
from wcs.libs.messages import languages
from wcs.libs.skills import Skill, Ultimate

__all__ = ["PythonRace"]

class PythonRace(RaceBase):
    """
    This object will be used to hold all information about race specifications;
    this will NOT include player specific information as that is held in the
    RaceCache for each individual player. The idea of this object is to store
    information such as the name of the race, the skill base of the race and
    also provide functionality to create / modify these attributes. This race
    instance loads the race from the directory of:
    ../wcs/race_folder/<racename>/<racename>.py
    """
    def __init__(self, raceName):
        """
        Constructor, executed automatically when a new object is created. Ensure
        that we assign the default variables and execute anything that needs
        to be created at run time.

        @param string raceName The name of the race to be created
        """
        from wcs.libs.races import races
        
        races[raceName] = self
        RaceBase.__init__(self, raceName, self.__class__)
        es.load("wcs/race_folder/%s" % raceName)
        addonList = map(lambda x: x.__name__, es.addons.getAddonList())
        if ("wcs.race_folder.%(r)s.%(r)s" % {'r': raceName}) not in addonList:
            raise ImportError("Race '%s' has encountered an error during load" %
                               raceName)

    def __del__(self):
        """
        Derfault deconstructor, destroy and unregister and variables which were
        created at construction which won't be destroyed automatically by the
        garbage collector.
        """
        es.unload("wcs/race_folder/%s" % self.name)

    def loadStrings(self):
        """
        Loads a langlib strings and langlib object which uses the ConfigObj
        constructor to construct a virtual ConfigObj from a dictionary. The
        higher API allows for the __call__ method to be executed as expected
        from a langlib object. To support backwards compatability we need to
        test to see if the strings.ini exists within the races folder, if so
        cut it out and overwrite any information within the racestrings.ini
        then remove the old method of adding langlib strings as we no prefer
        a grouped method as it means one single place for accessing diretories.

        @retun langlib.Strings ConfigObj wrapper for language strings for the
                               race object.
        """
        raceStringPath = DATA_PATH.joinpath(self.name, "strings.ini")
        if raceStringPath.exists():
            individualLanguageString = langlib.Strings(str(raceStringPath))
            languages.addLangString(self.name, individualLanguageString)
            languages.save()
            raceStringPath.remove()
        return langlib.Strings(languages[self.name])

    def config(self):
        """
        Returns the configuration object which is used to manage the
        configurations for each race.

        @return ConfigObject The instance for the configuration file.
        """
        return ConfigObject(self.name)

    def registerSkill(self, name, maxLevel, levelInterval, description):
        """
        Registers a skill for the race. This just stores the Skill
        object within the skills dictionary attribute.

        @param string name The name of the skill
        @param integer minLevel The minimum level required to purchase the skill
        @param integer maxLevel The maximum level this skill can go to
        @param string description A short description explaining the skill.
        """
        self.skills[name] = Skill(name, maxLevel, levelInterval, description)
        self.skillOrder.append(name)
        
    def registerUltimate(self, name, minLevel, maxLevel, levelInterval,
                                                                  description):
        """
        Registers an ultimate for the race. This just stores the ultimate
        object within the skills dictionary attribute.

        @param string name The name of the skill
        @param integer minLevel The minimum level required to purchase the skill
        @param integer maxLevel The maximum level this skill can go to
        @param integer levelInterval The intervals between possible purchases
        @param string description A short description explaining the ultimate.
        """
        self.skills[name] = Ultimate(name, minLevel, maxLevel, levelInterval,
                                                                  description)
        self.skillOrder.append(name)

    def registerMinLevel(self, minLevel):
        """
        This ensures that the race can only be played when the player reaches
        a specific total level. This allows the race to be unselectable until a
        user gets at least the specified levels using other races.

        @param integer minLevel The minimum level before users can play the race
        """
        self.minLevel = minLevel

    def registerTeamLimit(self, teamLimit):
        """
        This ensures that only a certain amount of player's on the same team
        can play as this race at one time. This makes it so that overpowered
        races can't unbalance the teams.

        @param integer teamLimit The amount of players allowed to play this
                                 race on the same team.
        """
        self.teamLimit = teamLimit

    def registerTeam(self, team):
        """
        This registers the race to a specific team. This means that only players
        on the specified team may use this race. If the user changes team whilst
        a race with a team restriction is active and they join a restricted
        team, then their race is changed to the first race without a
        restriction.

        @param str|int team The team to register the restriction
        """
        if isinstance(team, str):
            if team.isdigit():
                team = int(team)
            else:
                team = team.lower().strip("#")
                try:
                    team = {'t':2, 'ct':3, 'c':3}[team]
                except KeyError:
                    team = int(team)
        if isinstnace(team, int):
            if team in (2, 3):
                self.team = team

    def registerMaxLevel(self, maxLevel):
        """
        Registers a maximum level that a race may be able to level up to. This
        means that once they reach their maximum level, they cannot level past
        that and the XP will just loop over and over. This stops people from
        whoring an overpowered race to get global levels.

        @param int maxLevel The maximum level of the race
        """
        self.maxLevel = maxLevel

    def registerSteamid(self, *args):
        """
        Registers a list of SteamIDs that only have access to this race. This in
        fact will make it a "private race" and will not display in generic
        user's race list.

        @param args A list of steamids which have access to this race
        """
        if not args:
            raise TypeError("registerSteamid() takes more than 0 arguments")
        for steamidGroup in args:
            if not hasattr(steamidGroup, "__iter__"):
                steamidGroup = (steamidGroup, )
            for steamid in steamidGroup:
                self.steamid.add(steamid)

    def registerAuthorization(self, authorization):
        """
        Registers an authorization capability to be assigned to this race. This
        means only authorized users with this capability will be able to see
        / use the race in the race list.

        @param str authorization The auth capability 
        """
        self.authorization = authorization

    def registerWeaponRestriction(self, restrictionType, *args):
        """
        This function restricts weapons specifically for this race. It allows
        admins to specify whether weapons will be blocked or allowed. This
        will restrict users as to what weapons they can pick up / buy.

        @param string restrictType Either 'block'/'allow' which specifies how
                                   the restrictions will imply.
        @param iterable weapons A list of weapons to restrict.
        """
        if not args:
            raise TypeError("registerWeaponrestriction() expected 2+ args," +
                            " (received 1)")
        if restrictionType.lower() == "allow only":
            self.weaponRestrictions = set(weaponlib.getWeaponNameList("#all"))
        else:
            self.weaponRestrictions = set()
        for weaponBlock in args:
            if not hasattr(weaponBlock, "__iter__"):
                weaponBlock = (weaponBlock, )
            for weaponRestriction in weaponBlock:
                for weapon in weaponRestriction.split(","):
                    weaponList = weaponlib.getWeaponNameList(weapon)
                    for weapon in weaponList:
                        if restrictionType.lower() == "allow only":
                            if weapon in self.weaponRestrictions:
                                self.weaponRestrictions.remove(weapon)
                        else:
                            self.weaponRestrictions.add(weapon)